/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package MF1DSolver;

import FEMShapeFunction1D.FEMShapeFunction1D1;
import Integration.IFunction1D;
import MathLib.HashMatrix.Gauss;
import MathLib.HashMatrix.HashMatrix;
import MeshlessShapeFunctions.JMeshlessInterpolationFunction1DCoupled2;
import MeshlessShapeFunctions.Particle;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import syntaxanalyser.PostfiksX;

/**
 *
 * @author mark_o
 */
public class MF1DSolverCoupled {
    protected ArrayList<Particle> NodeList;
    protected ArrayList<JMeshlessInterpolationFunction1DCoupled2> ListOfShapeFunction;
    protected ArrayList<FEMShapeFunction1D1> ListOfFEMFunctions;
    protected HashMatrix A;
    protected double[] b;
    //protected double K;
    //protected double Pekle;
    //protected double convec;
    //protected String Func="10";
    String pString="1";
    String wString="0";
    String qString="10";
    String fString="100";

        IFunction1D p;
        IFunction1D w;
        IFunction1D q;
        IFunction1D f;


    double left;
    double right;

    boolean DirihetA;
    double AVal;
    boolean DirihetB;
    double BVal;


    public void generate(){

        p = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(pString, x);
                } catch (Exception ex) {
                    Logger.getLogger(MF1DSolver.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        w = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(wString, x);
                } catch (Exception ex) {
                    Logger.getLogger(MF1DSolver.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        q = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(qString, x);
                } catch (Exception ex) {
                    Logger.getLogger(MF1DSolver.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        f = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(fString, x);
                } catch (Exception ex) {
                    Logger.getLogger(MF1DSolver.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };


        ArrayList<ArrayList<Particle>> ParticleSupport = generateParticleSupport();
        for (int i = 0; i < ParticleSupport.size(); i++) {
            ListOfShapeFunction.get(i).setNodeList(ParticleSupport.get(i));
        }

//        A = new HashMatrix(HashMatrix.ARRAY_TYPE, NodeList.size());
//        b = new double[NodeList.size()];
        int NN = ListOfFEMFunctions.size()+ListOfShapeFunction.size();
        A = new HashMatrix(HashMatrix.ARRAY_TYPE, NN);
        b = new double[NN];
        ElementMatrixGeneratorMF1DCoupled gen = new ElementMatrixGeneratorMF1DCoupled();

        
        for (int i = 0; i < ParticleSupport.size(); i++) {
            ArrayList<Particle> arrayList = ParticleSupport.get(i);
            gen.setPhi1(ListOfShapeFunction.get(i));
            for (int j = 0; j < arrayList.size(); j++) {
                gen.setPhi2(ListOfShapeFunction.get(arrayList.get(j).getNumber()));
                gen.update();
                A.setValue(i, arrayList.get(j).getNumber(), gen.generateKeElement(p) + gen.generateMeElement(q) + gen.generatePeElement(w));
            }
            //for (int j = 0; j < ParticleSupport.size(); j++) {
            //    gen.setPhi2(ListOfShapeFunction.get(j));
            //    gen.update();
            //    A.setValue(i, j, K*gen.generateKeElement() + convec*gen.generateMeElement() + Pekle*gen.generatePeElement());
            //}
                b[i]= gen.generateFeElement(f);


        }
    }

    public double[] solve(){
        //LUFactorization lu = new LUFactorization(A);
            Gauss lu = new Gauss(A);
        return lu.calculate(b);
    }

    public double[] solvePenalty(){

        double MaxC = 1000000000000.0;

        if(DirihetA&&DirihetB){

            for(int i=0;i<b.length;i++){
                double tmp2 = ListOfShapeFunction.get(i).calculate(right);
                double tmp1 = ListOfShapeFunction.get(i).calculate(left);
                for(int j=0;j<b.length;j++){
                    A.setValue(i, j,A.getValue(i, j)+ MaxC*(tmp1*ListOfShapeFunction.get(j).calculate(left) +
                            tmp2*ListOfShapeFunction.get(j).calculate(right)));
                }
                b[i]+=MaxC*(BVal*tmp2+AVal*tmp1);
            }
        }else{
            if(DirihetA){
                for(int i=0;i<b.length;i++){
                    double tmp = ListOfShapeFunction.get(i).calculate(left);
                    for(int j=0;j<b.length;j++){
                        A.setValue(i, j,A.getValue(i, j)+ MaxC*(tmp*ListOfShapeFunction.get(j).calculate(left)));
                    }
                    b[i]+=MaxC*(AVal*tmp);
                }
            }else{
                for (int i = 0; i < ListOfShapeFunction.size(); i++) {
                    JMeshlessInterpolationFunction1DCoupled2 jMeshlessInterpolationFunction1D = ListOfShapeFunction.get(i);
                    b[i]+=AVal*jMeshlessInterpolationFunction1D.calculate(left);
                }
            }

            if(DirihetB){

                for(int i=0;i<b.length;i++){
                    double tmp = ListOfShapeFunction.get(i).calculate(right);
                    for(int j=0;j<b.length;j++){
                        A.setValue(i, j,A.getValue(i, j)+ MaxC*(tmp*ListOfShapeFunction.get(j).calculate(right)));
                    }
                    b[i]+=MaxC*(BVal*tmp);
                }
            }else{
                for (int i = 0; i < ListOfShapeFunction.size(); i++) {
                    JMeshlessInterpolationFunction1DCoupled2 jMeshlessInterpolationFunction1D = ListOfShapeFunction.get(i);
                    b[i]+=BVal*jMeshlessInterpolationFunction1D.calculate(right);
                }
            }
        }

        //Dirihlet a:
        //for(int i=0;i<b.length;i++){
        //    A.setValue(0, i,A.getValue(0, i)+ MaxC*ListOfShapeFunction.get(i).calculate(left)*ListOfShapeFunction.get(0).calculate(left));
        //}
        //b[0]+=0;

        //Dirihlet b:
        //for(int i=0;i<b.length;i++){
        //    A.setValue(b.length-1, i,A.getValue(b.length-1, i)+ MaxC*ListOfShapeFunction.get(i).calculate(right)*ListOfShapeFunction.get(b.length-1).calculate(right));
        //}
        //b[b.length-1]+=0;
        //LUFactorization lu = new LUFactorization(A);
            Gauss lu = new Gauss(A);
        return lu.calculate(b);
    }

    public double[] solveLagrangeMulti(){

        int n = A.getN();
        HashMatrix A2=null;
        double[] tmpb=null;

        if(DirihetA&&DirihetB){

            A2 = new HashMatrix(HashMatrix.ARRAY_TYPE, n+2);
            tmpb = new double[n+2];
            double tmp = ListOfShapeFunction.get(0).calculate(left);
            for (int i = 0; i < b.length; i++) {
                for (int j = 0; j < b.length; j++) {
                    A2.setValue(i, j, A.getValue(i, j));
                }
            }
            for(int i=0;i<n;i++){
                A2.setValue(n, i, ListOfShapeFunction.get(i).calculate(left)*tmp);
                A2.setValue(i, n, ListOfShapeFunction.get(i).calculate(left)*tmp);
                tmpb[i] = b[i];
            }
            tmpb[n] = tmp*AVal;

            tmp = ListOfShapeFunction.get(ListOfShapeFunction.size()-1).calculate(right);
            for(int i=0;i<n;i++){
               A2.setValue(n+1, i, ListOfShapeFunction.get(i).calculate(right)*tmp);
               A2.setValue(i, n+1, ListOfShapeFunction.get(i).calculate(right)*tmp);
            }
            tmpb[n+1] = tmp*BVal;

        }else{
            if(DirihetA){
                A2 = new HashMatrix(HashMatrix.ARRAY_TYPE, n+1);
                tmpb = new double[n+1];
                for (int i = 0; i < b.length; i++) {
                    for (int j = 0; j < b.length; j++) {
                        A2.setValue(i, j, A.getValue(i, j));
                    }
                }

                double tmp = ListOfShapeFunction.get(0).calculate(left);
                for(int i=0;i<n;i++){
                    A2.setValue(n, i, ListOfShapeFunction.get(i).calculate(left)*tmp);
                    A2.setValue(i, n, ListOfShapeFunction.get(i).calculate(left)*tmp);
                    tmpb[i] = b[i];
                }
                tmpb[n] = tmp*AVal;
            }else{
                for (int i = 0; i < ListOfShapeFunction.size(); i++) {
                    JMeshlessInterpolationFunction1DCoupled2 jMeshlessInterpolationFunction1D = ListOfShapeFunction.get(i);
                    b[i]+=AVal*jMeshlessInterpolationFunction1D.calculate(left);
                }
            }

            if(DirihetB){
                A2 = new HashMatrix(HashMatrix.ARRAY_TYPE, n+1);
                tmpb = new double[n+1];
                for (int i = 0; i < b.length; i++) {
                    for (int j = 0; j < b.length; j++) {
                        A2.setValue(i, j, A.getValue(i, j));
                    }
                }

                double tmp = ListOfShapeFunction.get(ListOfShapeFunction.size()-1).calculate(right);
                for(int i=0;i<n;i++){
                   A2.setValue(n, i, ListOfShapeFunction.get(i).calculate(right)*tmp);
                   A2.setValue(i, n, ListOfShapeFunction.get(i).calculate(right)*tmp);
                }
                tmpb[n] = tmp*BVal;
            }else{
                for (int i = 0; i < ListOfShapeFunction.size(); i++) {
                    JMeshlessInterpolationFunction1DCoupled2 jMeshlessInterpolationFunction1D = ListOfShapeFunction.get(i);
                    b[i]+=BVal*jMeshlessInterpolationFunction1D.calculate(right);
                }
            }
        }

        //LUFactorization lu = new LUFactorization(A);
        Gauss lu = new Gauss(A2);
        return lu.calculate(tmpb);
    }

    public double getAVal() {
        return AVal;
    }

    public void setAVal(double AVal) {
        this.AVal = AVal;
    }

    public double getBVal() {
        return BVal;
    }

    public void setBVal(double BVal) {
        this.BVal = BVal;
    }

    public boolean isDirihetA() {
        return DirihetA;
    }

    public void setDirihetA(boolean DirihetA) {
        this.DirihetA = DirihetA;
    }

    public boolean isDirihetB() {
        return DirihetB;
    }

    public void setDirihetB(boolean DirihetB) {
        this.DirihetB = DirihetB;
    }

    public String getfString() {
        return fString;
    }

    public void setfString(String fString) {
        this.fString = fString;
    }

    public String getpString() {
        return pString;
    }

    public void setpString(String pString) {
        this.pString = pString;
    }

    public String getqString() {
        return qString;
    }

    public void setqString(String qString) {
        this.qString = qString;
    }

    public double getRight() {
        return right;
    }

    public void setRight(double right) {
        this.right = right;
    }

    public String getwString() {
        return wString;
    }

    public void setwString(String wString) {
        this.wString = wString;
    }

    public double getLeft() {
        return left;
    }

    public void setLeft(double left) {
        this.left = left;
    }


    public ArrayList<JMeshlessInterpolationFunction1DCoupled2> getListOfShapeFunction() {
        return ListOfShapeFunction;
    }

    public void setListOfShapeFunction(ArrayList<JMeshlessInterpolationFunction1DCoupled2> ListOfShapeFunction) {
        this.ListOfShapeFunction = ListOfShapeFunction;
    }

    public ArrayList<Particle> getNodeList() {
        return NodeList;
    }

    public void setNodeList(ArrayList<Particle> NodeList) {
        this.NodeList = NodeList;
    }

    private ArrayList<ArrayList<Particle>> generateParticleSupport(){
        ArrayList<ArrayList<Particle>> res = new ArrayList<ArrayList<Particle>>();
        //for (int i = 0; i < ListOfShapeFunction.size(); i++) {
        //    ArrayList<Particle> tmp = new ArrayList<Particle>();
        //    JMeshlessInterpolationFunction1D phi = ListOfShapeFunction.get(i);
            /*for (int j = 0; j < i; j++) {
            JMeshlessInterpolationFunction1D phiTMP = ListOfShapeFunction.get(j);
            if(Math.abs(phi.getXii()-phiTMP.getXii())<(Math.abs(phi.getRho()+phiTMP.getRho()))){
            tmp.add(new Particle(phiTMP.getXii(), 0.0, j));//TODO перевірити чи той номер вузла ні на шо не впливає .....
            }
            }*/
        //    for (int j = 0; j < ListOfShapeFunction.size(); j++) {
        //        JMeshlessInterpolationFunction1D phiTMP = ListOfShapeFunction.get(j);
        //        if(Math.abs(phi.getXii()-phiTMP.getXii())<(Math.abs(phi.getRho()+phiTMP.getRho()))){
        //            tmp.add(new Particle(phiTMP.getXii(), 0.0, j));//TODO перевірити чи той номер вузла ні на шо не впливає .....
        //        }
        //    }
        //    res.add(tmp);
        //}
        //return res;
        for (int i = 0; i < ListOfShapeFunction.size(); i++) {
            res.add(NodeList);
        }
        return res;
    }
}
